"""
代码请勿用于非法盈利,一切与本人无关,该代码仅用于学习交流,请阅览下载24小时内删除代码
走不走邀请都无所谓了,能走更好,不走也没关系,我的要求,
请勿擅自修改脚本注释,
请勿将脚本擅自分享传播至任何地方,请勿将邀请更改为自己的邀请拉取人头,
如果你这样做了,我是没办法怎么样你的,我只能删库无能狂怒
阅读：鱼儿阅读
new Env("鱼儿阅读")
cron: 9 9-21/2 * * *

走邀请: 立即参与 -> https://ye1114210222-1322422422.cos.ap-nanjing.myqcloud.com/index.html?upuid=1386000
(如无法打开，请复制链接在手机浏览器打开，获取最新入口)
@不走邀请: https://ye1114210222-1322422422.cos.ap-nanjing.myqcloud.com/index.html



第一步配置文件填写:export WXPUSER_TOKEN="AT_aYF2532tqjrD4dX90OrJsuiflscRureX"
    然后微信打开链接:https://wxpusher.zjiecode.com/wxuser/?type=1&id=50341#/follow
    关注wxpuser app 订阅公众号就能获取   你的uid
第二部配置文件填写:export WXPUSER_UID="你的uid"  # 多号就export WXPUSER_UID="你的uid1@你的uid2@...."  uid获取方式看第一步
第三步配置文件填写:export yeydcks='PHPSESSID............'
# 多号就 export yeydcks='PHPSESSID...........@PHPSESSID=.........'
cookie就是你的完整cookie都行!!!!!!

并发开关 export kl_multi='true'
export READ_USER_AGENT='你的手机微信阅读user-agent'
"""




import asyncio
import aiohttp
from typing import Optional, Dict
from urllib.parse import urlparse,parse_qs,quote
import time,random,json
import sys, logging,re
import os
logging.basicConfig(level=logging.INFO)

class template:
    def __init__(self, index:int, wxpuser_token:str, topicid:str, wxpuser_uid:str) -> None:
        self.index = index
        self.wxpuser_token = wxpuser_token
        self.topicid=topicid
        self.wxpuser_uid = wxpuser_uid
        ua = 'Mozilla/5.0 (Linux; Android 13; M2012K11AC Build/TKQ1.220829.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/117.0.0.0 Mobile Safari/537.36 MMWEBID/2651 MicroMessenger/8.0.42.2460(0x28002A58) WeChat/arm64 Weixin NetType/WIFI Language/en ABI/arm64'
        self.user_agent = os.getenv('READ_USER_AGENT',ua)
        self.sessions = aiohttp.ClientSession()
        self.logger = logging.getLogger(f"用户{self.index}")
        self.content = ''

    def log(self, msg):  # 改写一下日志
        self.logger.info(msg)
        # self.content += str(msg) + '\n'


    async def close(self):
        await self.sessions.close()

    async def request(self, url, method='get', data=None, add_headers: Optional[Dict[str, str]] = None, headers=None, dtype='json'):
        host = urlparse(url).netloc
        _default_headers = {
            "Host":host,
            "User-Agent": self.user_agent,
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "X-Requested-With":"com.tencent.mm",
            "Cookie": self.cookie
        }
        try:
            request_headers = headers or _default_headers
            if add_headers:
                request_headers.update(add_headers)
            async with getattr(self.sessions, method)(url, headers=request_headers, data=data) as response:
                if response.status == 200:
                    if dtype == 'json':
                        return await response.json()
                    else:
                        return await response.text()
                else:
                    self.log(f"请求失败状态码：{response.status}")
                    # 可以选择休眠一段时间再重试，以避免频繁请求
                    await asyncio.sleep(random.randint(3,5))  # 休眠1秒钟
        except Exception as e:
            self.log(f"请求出现错误：{e}")
            await asyncio.sleep(random.randint(3,5))  # 休眠1秒钟


    async def get_other_url(self):
        url = 'https://qmr.bypanghu.xyz/bwjl/pp'
        add_headers = {
            'Host':'qmr.bypanghu.xyz',
            "User-Agent": self.user_agent,
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "Referer": "https://ye1114210222-1322422422.cos.ap-nanjing.myqcloud.com/",
            "Origin":"https://ye1114210222-1322422422.cos.ap-nanjing.myqcloud.com",
            "sec-ch-ua":'"Android WebView";v="117", "Not;A=Brand";v="8", "Chromium";v="117"',
            "sec-ch-ua-platform":'"Android"',
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "cross-site"
        }
        async with self.sessions.get(url, headers=add_headers) as response:
            if response.status == 200:
                res = await response.text()
                res = json.loads(res)
                url = 'http://'+ urlparse(res['jump']).netloc
                return url
            else:
                self.log("获取base_url失败,改备用的url")
                url = 'https://bwjl1115170002-1316152458.cos.ap-nanjing.myqcloud.com'
                return url

    async def get_base_url(self):
        referer = await self.get_other_url()
        url = 'https://h5.127-server.xyz/entry/pp'
        add_headers = {
            "Referer": referer + "/",
            "Origin": referer,
            "sec-ch-ua":'"Android WebView";v="117", "Not;A=Brand";v="8", "Chromium";v="117"',
            "sec-ch-ua-platform":'"Android"',
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
        }
        async with self.sessions.get(url, headers=add_headers) as response:
            if response.status == 200:
                res = await response.json()
                self.url = 'http://'+ urlparse(res['jump']).netloc
            else:
                self.log("获取user_info_url失败,改备用的url")
                self.url = "http://h5153526.wdlvjj.bar"



    async def user_info(self):
        url = self.url + '/pipa_read'
        add_headers = {
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        }
        res = await self.request(url, add_headers=add_headers,dtype='text')
        if not res:
            self.log("获取用户信息失败")
            return
        # print(res)
        match = re.search(r'ID:(\d+)', res)
        id = match.group(1) if match else None
        match = re.search(r'余额：(.+)</p>', res)
        balance = match.group(1) if match else None
        match = re.search(r'今日已读(.+)篇，', res)
        self.read_num = match.group(1) if match else None
        self.log(f"ID:{id} 余额:{balance} 今日已读{self.read_num}篇")
        await asyncio.sleep(random.randint(3,5))

    async def get_article(self):
        url1 = self.url + '/read_task/get_read_url'
        add_headers = {
            "X-Requested-With": "XMLHttpRequest",
        }
        res = await self.request(url1, add_headers=add_headers)
        if not res:
            self.log("获取文章地址失败")
            return
        if 'jump' in res:
            self.log(f"文章地址：{res['jump']}")
            # if int(self.read_num) <= 3:
            #     self.log("🤡🤡🤡,今天没有手动去过检测吧,送你一程,我不干了")
            #     # await self.wxpuser(f"可乐阅读[用户{self.index}]请90秒阅读2-3篇过检测", quote(res['jump']))
            #     return
            # self.log("请90秒内读文章2-3篇,没过就算了,我就在原地死等90秒!!!!")
            # start_time = int(time.time())
            # while True:
            #     if await self.get_read_state():
            #         self.log(f"👌👌👌你已经打开了阅读链接,请耐心的阅读2-3篇文章")
            #         break
            #     if int(time.time())- start_time > 90:
            #         self.log(f"😓😓😓90秒到啦,本次阅读你放弃了,下次再来")
            #         return
            # end_time = int(time.time())
            # await asyncio.sleep((start_time+90)-end_time)
            await asyncio.sleep(random.randint(3,5))
            await self.jump_location(res['jump'])
        else:
            self.log(f"获取文章失败：{res}")

    async def jump_location(self, url):
        host = urlparse(url).netloc
        headers = {
            "Host":host,
            "User-Agent": self.user_agent,
            "Accept": "application/json, text/plain, */*",
            "Accept-Encoding": "gzip, deflate",
            "Accept-Language": "zh-CN,zh;q=0.9",
            "X-Requested-With":"com.tencent.mm",
        }
        urls = url + '&type=7'
        async with self.sessions.get(urls,headers=headers) as response:
            if response.status == 200:
                res = await response.text()
        parsed_url = urlparse(url)
        query_parameters = parse_qs(parsed_url.query)
        iu = query_parameters['iu'][0]
        url1 = f'https://h5.127-server.xyz/read_task/do_read?iu={iu}&type=7&pageshow'
        if '加载中' in res:
            self.log("加载阅读文章中")
            # 获取url的iu参数
            if iu is not None:
                await self.do_read(url1, url )
            else:
                self.log("获取url参数失败")
        else:
            self.log(f"加载不了")
            return
    async def do_read(self, url, referer, jkey=None,):
        if jkey is None:
            url1 = url + f'&r={round(random.uniform(0,1),16)}'
        else:
            url1 = url + f'&r={round(random.uniform(0,1),16)}&jkey={jkey}'
        add_headers = {
            "Referer": referer +'/',
            "Origin": referer,
            "X-Requested-With":"XMLHttpRequest"
        }
        await self.request(url1,'options', add_headers=add_headers, dtype='text')
        res = await self.request(url1,add_headers=add_headers)
        if not res:
            self.log("阅读失败")
            return
        if 'jkey' in res:
            # self.log(res['url'])
            if await self.verify_status(res['url']):
                pass
            else:
                return
            if 'success_msg' in res:
                self.log(f"{res['success_msg']}")
            else:
                self.log(f"阅读成功")
            await asyncio.sleep(random.randint(7,15))
            await self.do_read(url, referer, res['jkey'])
        else:
            self.log(f"本次阅读已完成,等等再来吧")

    async def verify_status(self, url):
        if 'chksm=' in url:
            self.log("😅😅😅😅出现检测文章了！")
            encoded_url = quote(url)
            await self.wxpuser(encoded_url)
            self.log("🤷‍♂️🤷‍♂️🤷‍♂️请20秒内点击阅读啦")
            time.sleep(20)
            return True
        else:
            self.log(f"😍😍😍这次阅读没有检测")
            return True

    async def with_draw(self):
        url = self.url +'/withdrawal'
        add_headers = {
            "Referer": self.url+ "/new",
        }
        res = await self.request(url,add_headers=add_headers,dtype='text')
        if not res:
            self.log("获取提现信息失败")
            return
        money = re.findall(r'<span>(.*?)</span>', res)[0]
        self.log(f"当前积分{money}=={round(float(money)/100, 2)}元")
        # if res['code'] == 0:
        #     self.log(f"{res['data']['user']['username']}当前积分{res['data']['user']['score']}=={round(float(res['data']['user']['score'])/100, 2)}元")
        tag = 60
        if float(money) > tag:
            draw_money = round(float(money),2)
            await self.do_withdraw(draw_money)
        # else:
        #     self.log(f"获取提现信息失败：{res}")
        #     return

    async def do_withdraw(self, amount):
        url = self.url + '/withdrawal/submit_withdraw'
        # data = f'amount={amount}&type=wx'
        data =f'channel=wechat&money={amount}'
        add_headers = {
            "Referer": self.url+ "/withdrawal",
            "Origin": self.url,
            "Content-Type": "application/x-www-form-urlencoded",
            "X-Requested-With":"XMLHttpRequest"
        }
        res = await self.request(url, 'post', data=data,add_headers=add_headers)
        if not res:
            self.log("提现失败")
            return
        # self.log(res)
        if res['code'] == 0:
            self.log(f"提现成功")
        else:
            self.log(f"提现失败：{res}")
        # if '"code":0' in res:
        #     self.log(f"提现成功")
        # else:
        #     self.log(f"提现失败：{res}")


    async def wxpuser(self, url):
        content = "检测文章-鱼儿%0A请在20秒内完成验证!%0A%3Cbody+onload%3D%22window.location.href%3D%27link%27%22%3E"
        content = content.replace('link', url)
        wxpuser_url = f'https://wxpusher.zjiecode.com/demo/send/custom/{self.wxpuser_uid}?content={content}'
        res = await self.request(wxpuser_url, 'get', headers={"Content-Type": "application/json"})
        if res['success'] == True:
            self.log(f"[通知]--->检测发送成功！")
        else:
            self.log(f"[通知]====>发送失败！！！！！")

    async def run(self, ck:str, sleep_time=None):#
        if sleep_time:
            print(f"[用户{self.index}][等待]:{sleep_time}秒,加点延迟是最好的")
            await asyncio.sleep(sleep_time)
        self.log(f"{'='*13}开始运行{'='*13}")
        await self.get_base_url()
        self.cookie = ck
        self.mmmmy = ck
        await self.user_info()
        await self.get_article()
        # self.cookie = ck  # 中途更换了一次cookie，提现要换回来
        await self.with_draw()
        self.log(f"{'='*13}运行结束{'='*13}")
        await self.close()

async def check_env():
    # 这里可以写完善一点的获取环境变量功能
    wxpuser_token = os.getenv("WXPUSER_TOKEN")
    topicid = os.getenv("WXPUSER_TOPICID")
    wxpuser_uid = os.getenv("WXPUSER_UID")
    cks = os.getenv('yeydcks')
    if cks is None:
        print("鱼儿阅读ck为空,请去抓包格式:'PHPSESSID=xxxxx' 多账户请用@分割")
        print('cookie填写:export yeydcks="PHPSESSID=xxxxx"')
        exit()
    if topicid is None and wxpuser_uid is None:
        print("wxpuser的topicid和WXPUSER_UID都为空,请至少填写其中一个")
        exit()
    correct_data = []
    ck_list = cks.split("@")
    wxpuser_list = wxpuser_uid.split('@')
    for index ,ck in enumerate(ck_list):
        if 'PHPSESSID' in ck:
            correct_data.append(ck)
        else:
            print(f"[账号{index+1}][错误]:填写格式不对正确的格式是在配置文件填写export yeydcks='PHPSESSID=xxxx....' 或者环境变量新建 变量名:yeydcks 值:PHPSESSID=xxxxx.   多账号用@分割")
    if len(correct_data) > len(wxpuser_list):
        print(f"[警告][格式]:wxpuser_uid的数量与填写cookie的数量不一致,将默认第一个wxpuser_uid填补完整")
        fill_count = len(ck_list) - len(wxpuser_list)
        wxpuser_list.extend([wxpuser_list[0]] * fill_count)
    return correct_data, wxpuser_list, topicid, wxpuser_token

async def main():
    cks_list, wxpuser_list, topicid, wxpuser_token = await check_env()
    api_url = 'http://110.41.145.200:8088'

    # 检查是否存在环境变量 multi
    use_concurrency = os.environ.get('kl_multi', 'false').lower() == 'true'
    tasks = []
    delay = os.getenv("gbyd_delay",'30')
    random_sleep_list = [i * random.randint(int(delay), int(delay)+15) for i in range(len(cks_list))]
    for index, ck in enumerate(cks_list):
        abc = template(index+1, wxpuser_token, topicid, wxpuser_list[index])
        task = abc.run(ck, random_sleep_list[index])
        tasks.append(task)
    if use_concurrency:  # 如果是true 那么就执行并发
        await asyncio.gather(*tasks)  # 并发执行任务
    else:  # 如果是false 那么就串行执行
        for task in tasks:
            await task

if __name__ == '__main__':
    asyncio.run(main())

